package cn.yunyichina.utils.security;

import cn.yunyichina.utils.constants.Encoding;
import cn.yunyichina.utils.digest.RSAUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Lullaby on 2016/12/12.
 */
public class SignUtil {

    /**
     * 微信请求参数签名
     *
     * @param params 参与签名参数
     * @param key    接口密码
     * @return
     */
    public static String wechatPaySign(Map<String, String> params, String key) {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuilder target = new StringBuilder();

        for (String k : keys) {
            String value = params.get(k);
            if (StringUtils.isNotBlank(value)) {
                target.append(k).append("=").append(value).append("&");
            }
        }

        target.append("key=").append(key);

        return DigestUtils.md5Hex(target.toString()).toUpperCase();
    }

    /**
     * 构建微信签名串
     *
     * @param params
     * @return
     */
    public static String getWechatSignString(Map<String, String> params) {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuffer target = new StringBuffer();
        for (String k : keys) {
            String value = params.get(k);
            if (StringUtils.isNotBlank(value)) {
                target.append(k).append("=").append(value).append("&");
            }
        }

        return target.deleteCharAt(target.length() - 1).toString();
    }

    /**
     * 微信支付签名验证
     *
     * @param params 验签参数
     * @param key    微信密钥
     * @return
     */
    public static boolean validateWechatPaySign(Map<String, String> params, String key) {
        return params.remove("sign").equals(wechatPaySign(params, key));
    }

    /**
     * 平安签名验签
     *
     * @param params
     * @return
     */
    public static boolean checkPacityPaySign(Map<String, String> params) {
        return params.isEmpty();
    }

    /**
     * 构建平安签名字符串
     *
     * @param params
     * @return
     * @throws Exception
     */
    public static String pacitySignContent(Map<String, String> params) throws Exception {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuffer target = new StringBuffer();

        for (String key : keys) {
            String value = params.get(key);
            if (StringUtils.isNotBlank(value)) {
                target.append(key).append("=").append(value).append("&");
            }
        }

        return target.deleteCharAt(target.length() - 1).toString();
    }

    /**
     * 平安签名
     *
     * @param params
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String pacitySign(Map<String, String> params, String privateKey) throws Exception {
        return RSAUtil.signSHA256(pacitySignContent(params), privateKey);
    }

    /**
     * 平安签名
     *
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String pacitySign(String content, String privateKey) throws Exception {
        return RSAUtil.signSHA256(content, privateKey);
    }

    /**
     * 验证平安签名
     *
     * @param params
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean verifyPacitySign(Map<String, String> params, String publicKey) throws Exception {
        String sign = params.remove("sign");
        return RSAUtil.verifySignSHA256(pacitySignContent(params), publicKey, sign);
    }

    /**
     * 验证平安签名
     *
     * @param content
     * @param publicKey
     * @param sign
     * @return
     * @throws Exception
     */
    public static boolean verifyPacitySign(String content, String publicKey, String sign) throws Exception {
        return RSAUtil.verifySignSHA256(content, publicKey, sign);
    }

    /**
     * 构建支付宝签名串(支付通知)
     *
     * @param params
     * @return
     */
    public static String buildAlipaySignContent(final Map<String, Object> params) {
        Map<String, Object> signMap = new HashMap<>();
        signMap.putAll(params);

        signMap.remove("pay_code");
        signMap.remove("pay_mode");
        signMap.remove("topic");

        String[] keys = new String[signMap.size()];
        signMap.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuilder target = new StringBuilder();
        for (String key : keys) {
            String value = (String) signMap.get(key);
            if (StringUtils.isNotBlank(value)) {
                target.append(key).append("=").append(value).append("&");
            }
        }

        return target.deleteCharAt(target.length() - 1).toString();
    }

    /**
     * 构建支付宝支付签名串
     *
     * @param params
     * @return
     */
    public static String getAlipaySignContent(Map<String, String> params) {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuilder target = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            if (StringUtils.isNotBlank(value)) {
                target.append(key).append("=").append(value).append("&");
            }
        }

        return target.deleteCharAt(target.length() - 1).toString();
    }

    /**
     * 构建支付宝支付请求串
     *
     * @param params
     * @return
     */
    public static String getAlipayEncodedContent(Map<String, String> params) throws UnsupportedEncodingException {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);

        StringBuilder target = new StringBuilder();
        for (String key : keys) {
            String value = params.get(key);
            if (StringUtils.isNotBlank(value)) {
                target.append(key).append("=").append(URLEncoder.encode(value, Encoding.UTF8)).append("&");
            }
        }

        return target.deleteCharAt(target.length() - 1).toString();
    }

}
